#include "Game.h"

namespace Dicewars
{
	Game::Game(Scene* newScene)
	{
		scene = newScene;
		currentRound = new GameRound();
		lastMoveTime = 0;
	}

	Game::~Game()
	{
	}
	
	void Game::Join(Player* newPlayer)
	{
		BoardTile* startTile = NULL;
		players.push_back(newPlayer);
		switch(newPlayer->GetNumber())
		{
			case 0:
			{
				startTile = board->GetBoardTile(board->GetWidth()-1,  board->GetHeight()-1);
				break;
			}
			case 1:
			{
				startTile = board->GetBoardTile(board->GetWidth()-1, 0);
				break;
			}
			case 2:
			{
				startTile = board->GetBoardTile(0, 0);
				break;
			}
			case 3:
			{
				startTile = board->GetBoardTile(0, board->GetHeight()-1);
				break;
			}
		}
		startTile->SetOwner(newPlayer, newPlayer->GetColor());
		for(int i = 0; i < 5 ; i++)
		{
			Die* newDie = new Die();
			startTile->PlaceDie(newDie);
			scene->AddObject(startTile->PushDie(newDie));
		}
	}

	void Game::Start()
	{
		playersIterator = players.begin();
		ChangePlayer();
		switch(activePlayer->GetPlayerType())
		{
			case ComputerPlayer:
			{
				currentRound->Start(5);
				break;
			}
			case HumanPlayer:
			{
				currentRound->Start(25);
				break;
			}
		}
	}
	
	void Game::Update(double secondsPassed)
	{
		for(turnResultsIterator = turnResults.begin(); turnResultsIterator != turnResults.end(); ++turnResultsIterator)
		{
			//TODO remove turnResults that are finished
			std::list<Animation*> animations = (*turnResultsIterator)->GetAnimationQue();
			std::list<Animation*>::const_iterator animationsIterator;
			for(animationsIterator = animations.begin(); animationsIterator != animations.end(); ++animationsIterator)
			{
				Animation* currentAnimation = (*animationsIterator);
				if(!(currentAnimation->IsFinished()))
				{
					currentAnimation->Update(secondsPassed);
				}
			}
			std::vector<Die*> diceToRemove = (*turnResultsIterator)->GetDiceToRemove();
			std::vector<Die*>::const_iterator diceToRemoveIterator;
			for(diceToRemoveIterator = diceToRemove.begin(); diceToRemoveIterator != diceToRemove.end(); ++diceToRemoveIterator)
			{
				scene->RemoveObject((*diceToRemoveIterator));
			}
			(*turnResultsIterator)->ClearDiceToRemove();
		}
		int timeLeft = currentRound->GetTimeLeft();
		if(timeLeft%2 && lastMoveTime != timeLeft)
		{
				if(activePlayer->GetPlayerType() == ComputerPlayer)
				{
					PerformAITurn();
					lastMoveTime = timeLeft;
				}
		}
		if(timeLeft <= 0)
		{
			FinishRound();
			ChangePlayer();
			activePlayer->ResetResults();
			switch(activePlayer->GetPlayerType())
			{
				case ComputerPlayer:
				{
					currentRound->Start(5);
					break;
				}
				case HumanPlayer:
				{
					currentRound->Start(25);
					break;
				}
			}
		}
		else
		{
			statusBar->SetTimeCounterValue(timeLeft);
			statusBar->SetDiceCounterValues(activePlayer->GetAttackerResult(), activePlayer->GetDefenderResult());
		}
	}
	
	void Game::FinishRound()
	{
		board->SetSelectedTile(NULL);
		std::vector<BoardTile*> playerTiles = board->GetTilesOwnedByPlayer(activePlayer);
		unsigned int tilesOwned = playerTiles.size();
		std::srand(time(0));
		for(int i = 0; i < tilesOwned; i++)
		{
			int randomNumber = (rand()%tilesOwned);
			BoardTile* randomTile = playerTiles.at(randomNumber);
			Die* newDie = new Die();
			randomTile->PlaceDie(newDie);
			scene->AddObject(randomTile->PushDie(newDie));
		}
	}

	void Game::PerformTurn(BoardTile* startTile, BoardTile* endTile)
	{
		switch(board->GetMoveMode(startTile, endTile, activePlayer))
		{
			case MoveDice:
			{
				activePlayer->ResetResults();
				turnResults.push_back(activePlayer->PerformMove(startTile, endTile));
				board->SetSelectedTile(endTile);
				break;
			}
			case Attack:
			{
				turnResults.push_back(activePlayer->PerformAttack(startTile, endTile));
				board->SetSelectedTile(endTile);
				break;
			}
			case Cancel:
			{
				break;
			}
			case Reselect:
			{
				board->SetSelectedTile(endTile);
				break;
			}
		}
	}
	
	void Game::PerformAITurn()
	{
		std::srand(time(0));
		std::vector<Vector4> allowedTurns = GetAllowedTurns();
		if(allowedTurns.size() > 0)
		{
			int possibleTurnCount = allowedTurns.size();
			int randomNumber = (rand()%possibleTurnCount);
			std::vector<Vector4>::iterator turnIterator = allowedTurns.begin() + randomNumber;
			Vector4 turn = (*turnIterator);
			Vector2 startPosition = Vector2(turn.x, turn.y);
			Vector2 endPosition = Vector2(turn.z, turn.w);
			BoardTile* startTile = board->GetBoardTile(startPosition.x, startPosition.y);
			BoardTile* endTile = board->GetBoardTile(endPosition.x, endPosition.y);
			switch(board->GetMoveMode(startTile, endTile, activePlayer))
			{
				case Attack:
				{
					turnResults.push_back(activePlayer->PerformAttack(startTile, endTile));				
					break;
				}
				case MoveDice:
				{
					activePlayer->ResetResults();
					turnResults.push_back(activePlayer->PerformMove(startTile, endTile));				
					break;
				}
			}
		}
	}
	
	void Game::ChangePlayer()
	{
		if(playersIterator != players.end())
		{
			activePlayer = (*playersIterator);
			statusBar->SetTimeCounterColor(activePlayer->GetColor()[0],activePlayer->GetColor()[1],activePlayer->GetColor()[2]);
			++playersIterator;
		}
		else
		{
			playersIterator = players.begin();
			activePlayer = (*playersIterator);
			statusBar->SetTimeCounterColor(activePlayer->GetColor()[0],activePlayer->GetColor()[1],activePlayer->GetColor()[2]);
			++playersIterator;
		}	
		statusBar->SetActivePlayeryType(activePlayer->GetPlayerType());
	}

	Player* Game::GetActivePlayer()
	{
		return activePlayer;
	}
	
	void Game::CancelRound()
	{
		currentRound->Break();	
	}
	
	void Game::AddStatusBar(StatusBar* bar)
	{
		statusBar = bar;
	}
	
	void Game::AddBoard(Board* gameBoard)
	{
		board = gameBoard;
		for(int w = 0;  w < board->GetWidth(); w++)
		{
			for(int h = 0; h < board->GetHeight(); h++)
			{
				scene->AddObject(board->GetBoardTile(w, h));
			}
		}
	}
	
	std::vector<Vector4> Game::GetAllowedTurns()
	{
		//HACK current and destination coordinates are stored in x, y, z, w of a vector4
		std::vector<Vector4> allowedMoves;
		std::vector<BoardTile*> ownedTiles = board->GetTilesOwnedByPlayer(activePlayer);
		std::vector<BoardTile*>::const_iterator ownedTilesIterator;
		for(ownedTilesIterator = ownedTiles.begin(); ownedTilesIterator != ownedTiles.end(); ++ownedTilesIterator)
		{
			BoardTile* currentTile = (*ownedTilesIterator);
			Vector2 currentPosition = (*currentTile->GetPosition());
			Vector2 target0Position = Vector2(currentPosition.x + 1, currentPosition.y);
			Vector2 target1Position = Vector2(currentPosition.x - 1, currentPosition.y);
			Vector2 target2Position = Vector2(currentPosition.x, currentPosition.y + 1);
			Vector2 target3Position = Vector2(currentPosition.x, currentPosition.y - 1);
			BoardTile* target0 = board->GetBoardTile(target0Position.x, target0Position.y);
			BoardTile* target1 = board->GetBoardTile(target1Position.x, target1Position.y);
			BoardTile* target2 = board->GetBoardTile(target2Position.x, target2Position.y);
			BoardTile* target3 = board->GetBoardTile(target3Position.x, target3Position.y);
			if(target0 != NULL && target0->GetPosition() != NULL && board->MoveAllowed(currentTile, target0))
			{
				allowedMoves.push_back(Vector4(currentPosition.x, currentPosition.y, target0Position.x, target0Position.y));
			}
			if(target1 != NULL && target1->GetPosition() != NULL && board->MoveAllowed(currentTile, target1))
			{
				allowedMoves.push_back(Vector4(currentPosition.x, currentPosition.y, target1Position.x, target1Position.y));
			}
			if(target2 != NULL && target2->GetPosition() != NULL && board->MoveAllowed(currentTile, target2))
			{
				allowedMoves.push_back(Vector4(currentPosition.x, currentPosition.y, target2Position.x, target2Position.y));
			}
			if(target3 != NULL && target3->GetPosition() != NULL && board->MoveAllowed(currentTile, target3))
			{
				allowedMoves.push_back(Vector4(currentPosition.x, currentPosition.y, target3Position.x, target3Position.y));
			}
		}
		return allowedMoves;
	}
}